//go:build windows

package main

import (
	"image/color"
	"os"
	"syscall"
	"time"
	"unsafe"

	"fyne.io/fyne/v2"
	"fyne.io/fyne/v2/app"
	"fyne.io/fyne/v2/canvas"
	"fyne.io/fyne/v2/container"
	"fyne.io/fyne/v2/theme"
	"github.com/lxn/win"
)

// customTheme 自定义主题以确保一致的窗口样式
type customTheme struct{}

func (m customTheme) Color(name fyne.ThemeColorName, variant fyne.ThemeVariant) color.Color {
	return theme.DefaultTheme().Color(name, variant)
}

func (m customTheme) Font(style fyne.TextStyle) fyne.Resource {
	return theme.DefaultTheme().Font(style)
}

func (m customTheme) Icon(name fyne.ThemeIconName) fyne.Resource {
	return theme.DefaultTheme().Icon(name)
}

func (m customTheme) Size(name fyne.ThemeSizeName) float32 {
	return theme.DefaultTheme().Size(name)
}

// 全局窗口句柄变量
var hwnd win.HWND

// 全局应用实例引用
var myApp fyne.App

// 定时器引用
var mainTicker *time.Ticker

// 右键菜单常量
const (
	MENU_EXIT_ID = 1001
)

// cleanupResources 用于清理程序资源
func cleanupResources() {
	// 停止定时器
	if mainTicker != nil {
		mainTicker.Stop()
	}
}

func main() {
	// 创建应用 - 使用唯一ID确保应用实例正确管理
	myApp = app.NewWithID("timer.clock")

	// 设置自定义主题
	myApp.Settings().SetTheme(&customTheme{})

	// 全局清理钩子 - 在程序退出时执行资源清理
	defer cleanupResources()

	// 创建窗口，不设置标题
	myWindow := myApp.NewWindow("")
	// 设置窗口为无装饰模式（隐藏标题栏）
	myWindow.SetMaster()
	myWindow.SetFixedSize(true)

	// 拦截关闭事件，提供自定义关闭行为
	myWindow.SetCloseIntercept(func() {
		myApp.Quit()
	})

	// 加载上海时区（UTC+8）
	shanghai, err := time.LoadLocation("Asia/Shanghai")
	if err != nil {
		shanghai = time.Local
	}

	// 创建UI元素 - 使用不透明的纯红色文本
	// 使用RGBA确保alpha通道为255（完全不透明）
	timeLabel := canvas.NewText("", color.RGBA{255, 0, 0, 255})
	timeLabel.TextSize = 48
	timeLabel.TextStyle = fyne.TextStyle{Bold: true}

	// 日期标签也使用完全不透明的红色
	dateInfoLabel := canvas.NewText("", color.RGBA{255, 0, 0, 255})
	dateInfoLabel.TextSize = 16

	// 背景颜色 - 使用半透明蓝色作为背景
	// 确保背景矩形将填充整个窗口
	// 增加透明度值，确保更好的视觉效果
	bgColor := canvas.NewRectangle(color.NRGBA{50, 100, 255, 180})

	// 创建内容容器，精确控制布局和内边距
	// 设置最小的内边距，确保只显示必要的内容
	contentBox := container.NewVBox(
		container.NewCenter(timeLabel),
		container.NewCenter(dateInfoLabel),
	)

	// 创建主内容，直接使用contentBox而不是添加额外的padding
	// 这样可以确保背景颜色完全覆盖整个窗口
	mainContent := container.NewStack(
		bgColor,
		contentBox,
	)

	// 设置窗口内容
	myWindow.SetContent(mainContent)

	// 设置窗口大小，精确匹配内容区域
	// 调整大小以确保只显示蓝色区域
	myWindow.Resize(fyne.NewSize(280, 120))

	// 获取当前进程ID，确保只修改我们自己的窗口
	currentPID := uint32(os.Getpid())

	// 启动一个goroutine来设置窗口属性和拖拽功能
	go func() {
		// 等待窗口显示
		time.Sleep(300 * time.Millisecond)

		// 使用更可靠的方法查找窗口句柄
		// 先尝试通过窗口类名查找Fyne应用窗口
		className, _ := syscall.UTF16PtrFromString("GLFW30")
		hwnd = win.FindWindow(className, nil)

		// 验证找到的窗口是否属于当前进程
		if hwnd != 0 {
			var windowPID uint32
			win.GetWindowThreadProcessId(hwnd, &windowPID)
			if windowPID != currentPID {
				// 如果不是当前进程的窗口，重新查找
				hwnd = 0
			}
		}

		// 如果通过类名没找到，尝试使用窗口标题查找
		if hwnd == 0 {
			windowTitle, _ := syscall.UTF16PtrFromString("")
			hwnd = win.FindWindow(nil, windowTitle)

			// 再次验证窗口是否属于当前进程
			if hwnd != 0 {
				var windowPID uint32
				win.GetWindowThreadProcessId(hwnd, &windowPID)
				if windowPID != currentPID {
					hwnd = 0
				}
			}
		}

		// 只在找到正确的窗口句柄时应用设置
		if hwnd != 0 {
			// 移除窗口边框和标题栏样式 - 彻底隐藏所有非必要元素
			style := win.GetWindowLongPtr(hwnd, win.GWL_STYLE)
			// 使用uintptr类型安全地移除所有窗口样式
			style &^= uintptr(win.WS_CAPTION)     // 移除标题栏
			style &^= uintptr(win.WS_THICKFRAME)  // 移除粗边框
			style &^= uintptr(win.WS_MINIMIZEBOX) // 移除最小化按钮
			style &^= uintptr(win.WS_MAXIMIZEBOX) // 移除最大化按钮
			style &^= uintptr(win.WS_BORDER)      // 移除边框
			style &^= uintptr(win.WS_SYSMENU)     // 移除系统菜单
			style &^= uintptr(win.WS_DLGFRAME)    // 移除对话框边框
			style &^= uintptr(win.WS_OVERLAPPED)  // 移除重叠窗口样式
			style &^= uintptr(win.WS_VISIBLE)     // 先移除可见性
			win.SetWindowLongPtr(hwnd, win.GWL_STYLE, style)

			// 重新添加可见性样式，确保窗口正常显示
			style |= uintptr(win.WS_VISIBLE)
			win.SetWindowLongPtr(hwnd, win.GWL_STYLE, style)

			// 实现窗口任意区域拖拽和右键菜单的核心逻辑
			// 保存原始窗口过程指针
			originalWndProcPtr := win.GetWindowLongPtr(hwnd, win.GWL_WNDPROC)

			// 创建一个回调函数用于处理窗口消息
			wndProc := syscall.NewCallback(func(hwnd win.HWND, msg uint32, wParam uintptr, lParam uintptr) uintptr {
				// 处理WM_NCHITTEST消息，这是Windows用来确定鼠标点击位置的消息
				if msg == win.WM_NCHITTEST {
					// 返回HTCAPTION表示鼠标点击了标题栏，这样整个窗口都可以拖拽
					return uintptr(win.HTCAPTION)
				}
				// 处理鼠标右键点击消息，显示菜单
				if msg == win.WM_RBUTTONDOWN {
					// 获取鼠标位置
					x := int32(lParam & 0xFFFF)
					y := int32(lParam >> 16)

					// 创建弹出菜单
					menu := win.CreatePopupMenu()
					if menu != 0 {
						// 直接使用syscall调用AppendMenuW函数
						user32 := syscall.MustLoadDLL("user32.dll")
						appendMenuW := user32.MustFindProc("AppendMenuW")
						menuText := syscall.StringToUTF16Ptr("退出")
						appendMenuW.Call(uintptr(menu), uintptr(win.MF_STRING), uintptr(1001), uintptr(unsafe.Pointer(menuText)))

						// 设置菜单位置并显示
						win.SetForegroundWindow(hwnd)
						result := win.TrackPopupMenu(
							menu,
							win.TPM_RIGHTALIGN|win.TPM_RETURNCMD,
							x,
							y,
							0,
							hwnd,
							nil,
						)

						// 处理菜单项选择
						if result == MENU_EXIT_ID {
							// 用户选择了退出，直接调用Quit确保可靠退出
							myApp.Quit()
							return 0
						}

						// 销毁菜单
						win.DestroyMenu(menu)
					}

					// 返回0表示消息已处理
					return 0
				}
				// 处理ESC键退出
						if msg == win.WM_KEYDOWN && wParam == uintptr(win.VK_ESCAPE) {
							// 用户按下了ESC键，直接退出程序
							myApp.Quit()
							return 0
						}
				// 对于其他消息，调用原始窗口过程
				return win.CallWindowProc(originalWndProcPtr, hwnd, msg, wParam, lParam)
			})

			// 设置新的窗口过程
			win.SetWindowLongPtr(hwnd, win.GWL_WNDPROC, wndProc)

			// 启用窗口透明度和特殊窗口样式
			// 设置窗口扩展属性，确保完全无边框、无阴影、无背景
			exStyle := win.GetWindowLongPtr(hwnd, win.GWL_EXSTYLE)
			exStyle |= uintptr(win.WS_EX_LAYERED)           // 启用层叠窗口样式，支持透明度
			exStyle |= uintptr(win.WS_EX_TOOLWINDOW)        // 设置为工具窗口，不会在任务栏显示
			exStyle &= ^uintptr(win.WS_EX_APPWINDOW)        // 确保不显示在任务栏
			exStyle &= ^uintptr(win.WS_EX_CLIENTEDGE)       // 移除客户区边缘
			exStyle &= ^uintptr(win.WS_EX_STATICEDGE)       // 移除静态边缘
			exStyle &= ^uintptr(win.WS_EX_DLGMODALFRAME)    // 移除对话框模态框架
			exStyle &= ^uintptr(win.WS_EX_WINDOWEDGE)       // 移除窗口边缘
			exStyle &= ^uintptr(win.WS_EX_OVERLAPPEDWINDOW) // 移除重叠窗口扩展样式
			win.SetWindowLongPtr(hwnd, win.GWL_EXSTYLE, exStyle)

			// 使用syscall直接调用SetLayeredWindowAttributes函数
			// 定义LWA_ALPHA和LWA_COLORKEY常量
			const (
				LWA_ALPHA    = 0x00000002
				LWA_COLORKEY = 0x00000001
			)

			// 获取user32.dll中的SetLayeredWindowAttributes函数
			user32 := syscall.MustLoadDLL("user32.dll")
			setLayeredWindowAttributes := user32.MustFindProc("SetLayeredWindowAttributes")

			// 同时设置颜色键和整体透明度
			// 0x00FFFFFF是白色，将白色区域设为透明
			// 降低透明度值到120，减少遮罩感
			setLayeredWindowAttributes.Call(uintptr(hwnd), 0x00FFFFFF, 120, LWA_COLORKEY|LWA_ALPHA)

			// 设置窗口始终置顶，满足用户置顶需求
			win.SetWindowPos(
				hwnd,
				win.HWND_TOPMOST,
				0, 0, 0, 0,
				win.SWP_NOMOVE|win.SWP_NOSIZE|win.SWP_NOACTIVATE,
			)

			// 无需注册全局热键，使用ESC键作为退出方式

			// 刷新窗口以应用新样式
			// 使用SWP_DRAWFRAME确保边框被正确重绘
			// 强制重绘整个窗口
			win.SetWindowPos(hwnd, 0, 0, 0, 0, 0, win.SWP_NOZORDER|win.SWP_NOMOVE|win.SWP_NOSIZE|win.SWP_FRAMECHANGED|win.SWP_DRAWFRAME)

			// 强制重绘客户区域
			win.InvalidateRect(hwnd, nil, true)
			win.UpdateWindow(hwnd)
		}
	}()

	// 定义更新时间的函数
	updateTime := func() {
		now := time.Now().In(shanghai)

		// 更新时间显示
		timeStr := now.Format("15:04:05")
		timeLabel.Text = timeStr
		timeLabel.Refresh()

		// 更新日期信息（使用英文避免编码问题）
		weekdayStr := now.Weekday().String()[:3]
		dateInfo := now.Format("2006-01-02 " + weekdayStr)
		dateInfoLabel.Text = dateInfo
		dateInfoLabel.Refresh()
	}

	// 初始更新
	updateTime()

	// 设置定时器，每秒更新一次
	mainTicker = time.NewTicker(time.Second)
	defer mainTicker.Stop()
	
	go func() {
		for range mainTicker.C {
			updateTime()
		}
	}()

	// 显示窗口并运行应用
	myWindow.ShowAndRun()
}
